#ifndef _TMATH_H_
#define _TMATH_H_


#include <stdarg.h>

#ifndef MIN
   #define MIN(x,y) ((x)<(y)?(x):(y))
#endif

#ifndef MAX
   #define MAX(x,y) ((x)>(y)?(x):(y))
#endif

#define  OPT_CAST(x)  (x *)


//#define NULL    0

#define NULL    ((void *)0)


//#define XMALLOC  malloc
//#define XFREE    free
//#define XREALLOC realloc
//#define XCALLOC  calloc

/* equalities */
#define MP_LT        -1   /* less than */
#define MP_EQ         0   /* equal to */
#define MP_GT         1   /* greater than */

#define MP_ZPOS       0   /* positive integer */
#define MP_NEG        1   /* negative */

#define MP_OKAY       0   /* ok result */
#define MP_MEM        -2  /* out of mem */
#define MP_VAL        -3  /* invalid input */
#define MP_RANGE      MP_VAL

#define MP_YES        1   /* yes response */
#define MP_NO         0   /* no response */

#define CHAR_BIT_Def  8         /* number of bits in a char */



/* default precision */
#ifndef MP_PREC
   #ifndef MP_LOW_MEM
      #define MP_PREC                 8     /* default digits of precision */
   #else
      #define MP_PREC                 8      /* default digits of precision */
   #endif   
#endif

#define DIGIT_BIT          28
typedef unsigned long      mp_digit;
//typedef unsigned __int64   mp_word;
typedef unsigned long long   mp_word;

#define MP_MASK          ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))

/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
#define MP_WARRAY               (1 << (sizeof(mp_word) * CHAR_BIT_Def - 2 * DIGIT_BIT + 1))

#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)

typedef int                mp_err;
#define DefineMaxAlloc 130
typedef struct  {
    int used, alloc, sign;
    mp_digit dp[DefineMaxAlloc];
} mp_int;

int mp_init (mp_int * a);
int mp_init_multi(mp_int *mp) ;
int mp_init_size (mp_int * a, int size);
void mp_clear (mp_int * a);
void mp_clear_multi(mp_int *mp);
int mp_cmp_mag (mp_int * a, mp_int * b);
int mp_cmp (mp_int * a, mp_int * b);
int mp_grow (mp_int * a, int size);
void mp_clamp (mp_int * a);
void mp_zero (mp_int * a);
int mp_copy (mp_int * a, mp_int * b);
void mp_exch (mp_int * a, mp_int * b);
int mp_init_copy (mp_int * a, mp_int * b);
void mp_set (mp_int * a, mp_digit b);
int mp_count_bits (mp_int * a);

int mp_lshd (mp_int * a, int b);
void mp_rshd (mp_int * a, int b);

int s_mp_add (mp_int * a, mp_int * b, mp_int * c);
int s_mp_sub (mp_int * a, mp_int * b, mp_int * c);


int mp_add (mp_int * a, mp_int * b, mp_int * c);
int mp_sub (mp_int * a, mp_int * b, mp_int * c);

int mp_mul_2d (mp_int * a, int b, mp_int * c);
int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d);
int mp_mod_2d (mp_int * a, int b, mp_int * c);

int mp_mul_2(mp_int * a, mp_int * b);
int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
int mp_2expt (mp_int * a, int b);

int mp_mul (mp_int * a, mp_int * b, mp_int * c);
int mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
int mp_mod (mp_int * a, mp_int * b, mp_int * c);
int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d);
int mp_sqr (mp_int * a, mp_int * b);

int mp_toom_mul(mp_int *a, mp_int *b, mp_int *c);
int mp_toom_sqr(mp_int *a, mp_int *b);
int mp_karatsuba_mul (mp_int * a, mp_int * b, mp_int * c);
int mp_karatsuba_sqr (mp_int * a, mp_int * b);

int mp_div_2(mp_int * a, mp_int * b);
int mp_div_3 (mp_int * a, mp_int *c, mp_digit * d);

int mp_exptmod_fast0 (mp_int * G, mp_int * X, mp_int * P, mp_int * Y);
int mp_montgomery_setup (mp_int * n, mp_digit * rho);
int mp_montgomery_calc_normalization (mp_int * a, mp_int * b);
int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);
int mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho);

int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
int fast_s_mp_sqr (mp_int * a, mp_int * b);

int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
int s_mp_sqr (mp_int * a, mp_int * b);

void bn_reverse (unsigned char *s, int len);

int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c);
int mp_to_unsigned_bin (mp_int * a, unsigned char *b);



int mp_read_unsigned_bin_s (mp_int * a, const unsigned char *b, int c);



#endif